package com.zzw.springboot.controller;

import com.zzw.springboot.annotation.RateLimit;
import com.zzw.springboot.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * Redis高级功能测试控制器
 */
@RestController
@RequestMapping("/redis")
public class RedisFeatureController {

    @Autowired
    private RedisLockUtil lockUtil;

    @Autowired
    private RedissonLockUtil redissonLockUtil;

    @Autowired
    private RedisPubSubUtil pubSubUtil;

    @Autowired
    private RedisRateLimiter rateLimiter;

    @Autowired
    private RedisRankingUtil rankingUtil;

    @Autowired
    private UserBehaviorAnalysisUtil behaviorUtil;

    /**
     * 测试分布式锁
     *
     * 注意：当前实现存在一个问题 - 如果业务执行时间超过锁的过期时间（timeout），
     * 锁可能会提前释放，导致其他线程能够获取锁并进入临界区，破坏了锁的排他性。
     *
     * 优化方案：使用Redisson框架的watchDog机制
     * Redisson的分布式锁实现了自动续期机制：
     * 1. 加锁时，设置一个初始的过期时间（例如30秒）
     * 2. 同时创建一个看门狗线程，默认每10秒检查一次
     * 3. 如果业务还在执行，看门狗会自动延长锁的过期时间
     * 4. 当持有锁的客户端崩溃或网络中断时，看门狗无法续期，锁会自动过期，避免死锁
     *
     * 使用Redisson的示例代码：
     * ```java
     * RLock lock = redisson.getLock("myLock");
     * try {
     *     // 无需指定过期时间，watchDog自动续期
     *     lock.lock();
     *     // 执行业务逻辑，无论多长时间
     *     doSomething();
     * } finally {
     *     lock.unlock();
     * }
     * ```
     */
    @RateLimit(period = 30, count = 50, limitType = RateLimit.LimitType.IP)
    @GetMapping("/lock/test")
    public Result testLock() {
        String lockKey = "test_lock";
        Map<String, Object> result = new HashMap<>();

        boolean useLegacyLock = false; // 切换锁实现方式

        if (useLegacyLock) {
            // 旧版本锁实现 - 不支持自动续期
            String value = UUID.randomUUID().toString();
            boolean locked = lockUtil.tryLock(lockKey, value, 30);
            result.put("locked", locked);
            result.put("implementation", "Redis SETNX");

            if (locked) {
                try {
                    // 模拟业务处理
                    Thread.sleep(1000);
                    result.put("message", "处理成功");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    result.put("message", "处理被中断");
                } finally {
                    boolean released = lockUtil.releaseLock(lockKey, value);
                    result.put("released", released);
                }
            } else {
                result.put("message", "获取锁失败");
            }
        } else {
            // 基于Redisson的锁实现 - 支持自动续期
            try {
                // 尝试获取锁，等待5秒，不设置超时时间(使用-1)，启用看门狗机制
                boolean locked = redissonLockUtil.tryLock(lockKey, 5, -1, TimeUnit.SECONDS);
                result.put("locked", locked);
                result.put("implementation", "Redisson WatchDog");

                if (locked) {
                    try {
                        // 模拟业务处理，即使很长时间也不会自动释放锁
                        long processingTime = 1000; // 5秒，超过了普通Redis锁的默认过期时间
                        result.put("processingTime", processingTime + "ms");
                        Thread.sleep(processingTime);
                        result.put("message", "处理成功 - 自动续期保持锁有效");
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        result.put("message", "处理被中断");
                    } finally {
                        // 释放锁
                        redissonLockUtil.unlock(lockKey);
                        result.put("released", true);
                    }
                } else {
                    result.put("message", "获取锁失败");
                }
            } catch (Exception e) {
                result.put("error", e.getMessage());
                result.put("message", "锁操作异常");
            }
        }

        return Result.success(result);
    }

    /**
     * 测试消息发布
     */
    @RateLimit(period = 60, count = 50, limitType = RateLimit.LimitType.INTERFACE)
    @PostMapping("/publish")
    public Result publish(@RequestParam String channel, @RequestParam String message) {
        pubSubUtil.publish(channel, message);
        return Result.success(200, "消息已发布");
    }

    /**
     * 测试限流功能
     */
    @GetMapping("/ratelimit/test")
    public Result testRateLimit(@RequestParam(required = false) String key) {
        if (key == null) {
            key = "test";
        }

        // 每60秒最多允许10次请求
        boolean allowed = rateLimiter.isAllowed(key, 60, 10);
        Map<String, Object> result = new HashMap<>();
        result.put("allowed", allowed);

        if (allowed) {
            result.put("message", "请求成功");
        } else {
            result.put("message", "请求过于频繁，请稍后再试");
        }

        return Result.success(result);
    }

    /**
     * 测试排行榜功能
     */
    @RateLimit(period = 30, count = 50, limitType = RateLimit.LimitType.IP)
    @GetMapping("/ranking/test")
    public Result testRanking() {
        String rankKey = "test_ranking";
        Map<String, Object> result = new HashMap<>();

        // 添加测试数据
        rankingUtil.addScore(rankKey, "user1", 100);
        rankingUtil.addScore(rankKey, "user2", 85);
        rankingUtil.addScore(rankKey, "user3", 95);
        rankingUtil.addScore(rankKey, "user4", 70);
        rankingUtil.addScore(rankKey, "user5", 60);

        // 获取排行榜前3名
        List<Map<String, Object>> topN = rankingUtil.getTopN(rankKey, 3);
        result.put("topN", topN);

        // 获取指定成员排名
        Long rank = rankingUtil.getRank(rankKey, "user3");
        result.put("user3Rank", rank != null ? rank + 1 : null);  // +1转为人类可读排名

        return Result.success(result);
    }

    /**
     * 测试用户行为分析
     */
    @RateLimit(period = 10, count = 50, limitType = RateLimit.LimitType.IP)
    @GetMapping("/behavior/view/{userId}")
    public Result recordUserView(@PathVariable Integer userId,
                                 @RequestParam(required = false) Integer viewerId) {
        // 记录用户被查看
        behaviorUtil.recordUserView(userId, viewerId);

        Map<String, Object> result = new HashMap<>();
        // 获取用户热度数据
        result.put("dailyHeat", behaviorUtil.getUserDailyHeat(userId));
        result.put("monthlyHeat", behaviorUtil.getUserMonthlyHeat(userId));

        // 获取热门用户排行
        result.put("hotUsersRanking", behaviorUtil.getHotUsersRanking(5));

        return Result.success(result);
    }

    /**
     * 获取行为统计
     */
    @RateLimit(period = 30, count = 50, limitType = RateLimit.LimitType.IP)
    @GetMapping("/behavior/stats")
    public Result getBehaviorStats() {
        try {
            Map<String, Long> dailyActionStats = behaviorUtil.getDailyActionStats();
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("dailyStats", dailyActionStats);
            return Result.success(resultMap);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("获取行为统计数据失败：" + e.getMessage());
        }
    }

    /**
     * 获取用户行为热力图数据
     */
    @RateLimit(period = 60, count = 50, limitType = RateLimit.LimitType.IP)
    @GetMapping("/behavior/heatmap")
    public Result getUserBehaviorHeatmap() {
        try {
            List<List<Object>> heatmapData = new ArrayList<>();

            // 模拟7天的数据
            for (int day = 0; day < 7; day++) {
                for (int hour = 0; hour < 24; hour++) {
                    int baseValue;

                    // 工作日工作时间段活跃度高
                    if (day > 0 && day < 6 && hour >= 9 && hour < 18) {
                        baseValue = 30 + new Random().nextInt(30);
                    }
                    // 周末活跃度普遍较低但在白天会高一些
                    else if ((day == 0 || day == 6) && hour >= 10 && hour < 20) {
                        baseValue = 15 + new Random().nextInt(20);
                    }
                    // 夜间活跃度低
                    else if (hour >= 0 && hour < 6) {
                        baseValue = 2 + new Random().nextInt(5);
                    }
                    // 其他时间段
                    else {
                        baseValue = 8 + new Random().nextInt(15);
                    }

                    List<Object> dataPoint = new ArrayList<>();
                    dataPoint.add(day);
                    dataPoint.add(hour);
                    dataPoint.add(baseValue);

                    heatmapData.add(dataPoint);
                }
            }

            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("heatmapData", heatmapData);
            return Result.success(resultMap);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("获取热力图数据失败：" + e.getMessage());
        }
    }

    /**
     * 获取接口限流统计数据
     */
    @GetMapping("/ratelimit/stats")
    public Result getRateLimitStats() {
        try {
            Map<String, Map<String, Long>> stats = rateLimiter.getInterfaceStats();

            // 转换数据结构为前端所需格式
            List<Map<String, Object>> result = new ArrayList<>();

            for (Map.Entry<String, Map<String, Long>> entry : stats.entrySet()) {
                String interfaceName = entry.getKey();
                Map<String, Long> counts = entry.getValue();

                Map<String, Object> item = new HashMap<>();
                item.put("interface", interfaceName);
                item.put("total", counts.getOrDefault("total", 0L));
                item.put("passed", counts.getOrDefault("passed", 0L));
                item.put("limited", counts.getOrDefault("limited", 0L));
                result.add(item);
            }

            // 如果没有数据，至少返回一些示例数据
            if (result.isEmpty()) {
                // 添加一些测试记录，方便前端显示
                for (int i = 1; i <= 5; i++) {
                    Map<String, Object> item = new HashMap<>();
                    item.put("interface", "接口" + i);
                    item.put("total", new Random().nextInt(50) + 10);
                    item.put("limited", new Random().nextInt(10));
                    item.put("passed", ((Number) item.get("total")).intValue() - ((Number) item.get("limited")).intValue());
                    result.add(item);
                }
            }

            return Result.success(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("获取接口限流统计失败：" + e.getMessage());
        }
    }
}
